package net.butfly.bus.invoker;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.butfly.albacore.exception.SystemException;
import net.butfly.bus.Constants;
import net.butfly.bus.Request;
import net.butfly.bus.Response;
import net.butfly.bus.TX;
import net.butfly.bus.config.bean.invoker.InvokerConfigBean;
import net.butfly.bus.util.TXUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class InvokerBase<C extends InvokerConfigBean> implements Invoker<C> {
	protected static Logger logger = LoggerFactory.getLogger(Invoker.class);

	protected Map<String, InvokerWrapper> reg = new HashMap<String, InvokerWrapper>();

	@Override
	public List<Object> getBeanList() {
		return new ArrayList<Object>();
	}

	@Override
	public void initialize(C config) {
		if (this.reg.isEmpty())
			try {
				logger.info("Invoker parsing...");
				for (Object bean : getBeanList()) {
					Class<?> implClass = bean.getClass();
					// DO not scan tx on implementation of facade.
					// scanMethodsForTX(implClass, bean);
					for (Class<?> clazz : implClass.getInterfaces())
						scanMethodsForTX(clazz, bean);
				}
				logger.info("Invoker parsed.");
			} catch (Exception _ex) {
				throw new SystemException(Constants.BusinessError.CONFIG_ERROR, _ex);
			}
	}

	@Override
	public void invoke(Response response, Request request) {
		String key = TXUtils.key(request.code(), request.version());
		InvokerWrapper ivk = reg != null ? reg.get(key) : null;
		if (ivk != null)
			try {
				Object[] args = request.arguments();
				Object obj = ivk.invoke(args);
				if (response != null)
					response.result(obj);
			} catch (IllegalArgumentException e) {
				throw new SystemException(Constants.BusinessError.INVOKE_ERROR, "调用业务逻辑类 " + ivk.getBean().getClass() + " 的方法 "
						+ ivk.getMethod().getName() + " 时出现请求的参数个数或类型异常，请检查请求的参数列表", e);
			} catch (IllegalAccessException e) {
				throw new SystemException(Constants.BusinessError.INVOKE_ERROR, "业务逻辑类 " + ivk.getBean().getClass() + " 的方法 "
						+ ivk.getMethod().getName() + " 可能不是public类型", e);
			} catch (InvocationTargetException e) {
				Throwable tw = e.getTargetException();
				String message = tw.getMessage();
				message = message != null ? message : "业务逻辑类 " + ivk.getBean().getClass() + " 的方法 " + ivk.getMethod().getName()
						+ " 调用异常";
				String errorCode = Constants.BusinessError.INVOKE_ERROR;
				try {
					Method m = tw.getClass().getMethod("getCode");
					if (m != null) {
						errorCode = m.invoke(tw).toString();
					}
				} catch (Exception ex) {

				}
				throw new SystemException(errorCode, message, e.getTargetException());
			}
		else {
			String keys = "";
			for (String k : reg.keySet())
				keys += k + ", ";
			keys = !keys.equals("") ? keys.substring(0, keys.length() - 2) : keys;
			throw new SystemException(Constants.BusinessError.CONFIG_ERROR, "没有找到交易 " + key + " 对应的业务逻辑对象(当前注册的交易如下:" + keys
					+ ")");
		}
	}

	private void scanMethodsForTX(Class<?> clazz, Object bean) throws SecurityException, NoSuchMethodException {
		while (clazz != null && !clazz.equals(Object.class)) {
			for (Method m : clazz.getDeclaredMethods()) {
				TX tx = m.getAnnotation(TX.class);
				if (tx != null) {
					String key = TXUtils.key(tx);
					logger.info("TX found:" + key + ".");
					if (reg.containsKey(key))
						logger.warn("TX duplicate: " + key + ", ignored...");
					else
						reg.put(key, new InvokerWrapper(bean, m));
				}
			}
			clazz = clazz.getSuperclass();
		}
	}
}
